package com.sdhs.paas.rc.app;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.fastjson.TypeReference;
import com.sdhs.paas.rc.bean.AppFileStoreBean;
import com.sdhs.paas.rc.bean.DocDiskBean;
import com.sdhs.paas.rc.bean.DocDownloadRecordBean;
import com.sdhs.paas.rc.bean.DocFolderBean;
import com.sdhs.paas.rc.bean.DocInfoBean;
import com.sdhs.paas.rc.bean.DocInfoVo;
import com.sdhs.paas.rc.bean.FileStoreBean;
import com.sdhs.paas.rc.configuration.RcserviceConfig;
import com.sdhs.paas.rc.dto.DocInfoDTO;
import com.sdhs.paas.rc.dto.req.DocInfoReqDTO;
import com.sdhs.paas.rc.dto.res.DocInfoResDTO;
import com.sdhs.paas.rc.service.DocDiskService;
import com.sdhs.paas.rc.service.DocDownloadRecordService;
import com.sdhs.paas.rc.service.DocFolderService;
import com.sdhs.paas.rc.service.DocInfoService;
import com.sdhs.paas.rc.service.FileStoreService;
import com.sdhs.paas.rc.util.Md5Util;
import com.sdhs.paas.sdk.base.common.BasePage;
import com.sdhs.paas.sdk.base.common.entity.PaginationEntity;
import com.sdhs.paas.sdk.base.dto.PageInfoDTO;
import com.sdhs.paas.sdk.base.utils.EntityDtoConvertUtil;
import com.sdhs.paas.sdk.core.PaasBaseException;
import com.sdhs.paas.sdk.core.PaasBaseRequest;
import com.sdhs.paas.sdk.core.PaasBaseResponse;
import com.sdhs.paas.sdk.core.RefreshableRestController;
import com.sdhs.paas.sdk.core.logger.Logger;
import com.sdhs.paas.sdk.core.logger.LoggerFactory;

/**
 * @author DocInfo
 * @version 1.0
 * @Title:  代码生成接口，用于接受前端传输过来的数据
 * @author kangjichang
 * @date 2018-12-03
 */
 
@RefreshableRestController
@RequestMapping(value = "/docInfo")
public class DocInfoController {
	
	private static Logger LOGGER  = LoggerFactory.getLogger(DocInfoController.class); 
	
	@Autowired
	private RcserviceConfig config;
	
    @Autowired
    private DocInfoService docInfoService;
    
    @Autowired
    private FileStoreService fileStoreService;
    
    @Autowired
    private DocDownloadRecordService docDownloadRecordService;
    
    @Autowired
    private DocDiskService docDiskService;
    
    @Autowired
    private DocFolderService docFolderService;
    
    /**
     * 分页查询接口
     * */
    @PostMapping("/getDocInfoPageList")
	public PaasBaseResponse<DocInfoResDTO> getDocInfoPageList(@RequestBody PaasBaseRequest<DocInfoReqDTO> docInfoReqDTO) {
    	DocInfoDTO docInfoDTO = docInfoReqDTO.getBody().getDocInfoDTO();
    	PageInfoDTO pageInfoDTO = docInfoReqDTO.getBody().getPageInfo();
    	
		BasePage pageRequest = new BasePage();
		pageRequest.setPage(pageInfoDTO.getPage());
		pageRequest.setCount(pageInfoDTO.getPageSize());
		
		DocInfoBean docInfoBean = EntityDtoConvertUtil.convertToEntity(docInfoDTO, DocInfoBean.class);
		PaginationEntity<DocInfoBean> page = docInfoService.getPageDocInfoList(pageRequest, docInfoBean);
    	PageInfoDTO resPageInfoDTO = new PageInfoDTO();
    	DocInfoResDTO docInfoResDTO = new DocInfoResDTO();
		resPageInfoDTO.setRowCount(page.getTotal());
		docInfoResDTO.setPageInfo(resPageInfoDTO);
		List<DocInfoBean> docInfoBeanList = page.getRows();
		List<DocInfoDTO> dtoList = new ArrayList<DocInfoDTO>();
		dtoList = EntityDtoConvertUtil.convertToDTOList(docInfoBeanList, new TypeReference<List<DocInfoDTO>>() {
		});
		docInfoResDTO.setDocInfoDTOList(dtoList);
    	return new PaasBaseResponse<>(docInfoResDTO);
	}
    
    @PostMapping("/getDocDownloadDetailPageList")
	public PaasBaseResponse<DocInfoResDTO> getDocDownloadDetailPageList(@RequestBody PaasBaseRequest<DocInfoReqDTO> docInfoReqDTO) {
    	DocInfoDTO docInfoDTO = docInfoReqDTO.getBody().getDocInfoDTO();
    	PageInfoDTO pageInfoDTO = docInfoReqDTO.getBody().getPageInfo();
    	
		BasePage pageRequest = new BasePage();
		pageRequest.setPage(pageInfoDTO.getPage());
		pageRequest.setCount(pageInfoDTO.getPageSize());
		
		DocInfoBean docInfoBean = EntityDtoConvertUtil.convertToEntity(docInfoDTO, DocInfoBean.class);
		PaginationEntity<DocInfoBean> page = docInfoService.getDocDownloadDetailPageList(pageRequest, docInfoBean);
    	PageInfoDTO resPageInfoDTO = new PageInfoDTO();
    	DocInfoResDTO docInfoResDTO = new DocInfoResDTO();
		resPageInfoDTO.setRowCount(page.getTotal());
		docInfoResDTO.setPageInfo(resPageInfoDTO);
		List<DocInfoBean> docInfoBeanList = page.getRows();
		List<DocInfoDTO> dtoList = new ArrayList<DocInfoDTO>();
		dtoList = EntityDtoConvertUtil.convertToDTOList(docInfoBeanList, new TypeReference<List<DocInfoDTO>>() {
		});
		docInfoResDTO.setDocInfoDTOList(dtoList);
    	return new PaasBaseResponse<>(docInfoResDTO);
	}
	
	/**
	 * 保存接口
	 * */
	@PostMapping("/saveDocInfo")
	public PaasBaseResponse<DocInfoResDTO> saveDocInfo(@RequestBody PaasBaseRequest<DocInfoReqDTO> docInfoReqDTO) {
		DocInfoDTO docInfoDTO = docInfoReqDTO.getBody().getDocInfoDTO();
		DocInfoBean docInfoBean = EntityDtoConvertUtil.convertToEntity(docInfoDTO, DocInfoBean.class);
		String uuid = UUID.randomUUID().toString().trim().replaceAll("-", "");
		docInfoBean.setId(uuid);
		docInfoBean.setIsDeleted(0);
		Boolean flag = docInfoService.saveDocInfo(docInfoBean);
		docInfoDTO.setId(uuid);
		DocInfoResDTO docInfoResDTO = new DocInfoResDTO();
		docInfoResDTO.setDocInfoDTO(docInfoDTO);
		return new PaasBaseResponse<>(docInfoResDTO);
	}
	
	/**
	 * 修改接口
	 * */
	@PostMapping("/updateDocInfo")
	public PaasBaseResponse<DocInfoResDTO> updateDocInfo(@RequestBody PaasBaseRequest<DocInfoReqDTO> docInfoReqDTO) {
		DocInfoDTO docInfoDTO = docInfoReqDTO.getBody().getDocInfoDTO();
		DocInfoBean docInfoBean = EntityDtoConvertUtil.convertToEntity(docInfoDTO, DocInfoBean.class);	
		Boolean flag = docInfoService.updateDocInfo(docInfoBean);
		DocInfoResDTO docInfoResDTO = new DocInfoResDTO();
		docInfoResDTO.setDocInfoDTO(docInfoDTO);
		return new PaasBaseResponse<>(docInfoResDTO);
	}
	
	/**
	 * 获取详情接口
	 * */
	@PostMapping("/getDocInfoDetail")
	public PaasBaseResponse<DocInfoResDTO> getDocInfoDetail(@RequestBody PaasBaseRequest<DocInfoReqDTO> docInfoReqDTO) {
		DocInfoDTO docInfoDTO = docInfoReqDTO.getBody().getDocInfoDTO();
		DocInfoBean docInfoBean = EntityDtoConvertUtil.convertToEntity(docInfoDTO, DocInfoBean.class);	
		docInfoBean = docInfoService.getDocInfoDetail(docInfoBean.getId());
		DocInfoResDTO docInfoResDTO = new DocInfoResDTO();
		docInfoResDTO.setDocInfoDTO(docInfoDTO);
		return new PaasBaseResponse<>(docInfoResDTO);
	}
	
	/**
	 * 删除接口
	 * */
	@PostMapping("/deleteDocInfo")
	public PaasBaseResponse<DocInfoResDTO> deleteDocInfo(@RequestBody PaasBaseRequest<DocInfoReqDTO> docInfoReqDTO) {
		DocInfoDTO docInfoDTO = docInfoReqDTO.getBody().getDocInfoDTO();
		DocInfoBean docInfoBean = EntityDtoConvertUtil.convertToEntity(docInfoDTO, DocInfoBean.class);	
		Boolean flag = docInfoService.deleteDocInfo(docInfoBean);
		DocInfoResDTO docInfoResDTO = new DocInfoResDTO();
		return new PaasBaseResponse<>(docInfoResDTO);
	}
	
	/**
	 * 文件上传接口
	 * @throws IOException 
	 * */
	@PostMapping("/fileUpload")
	public PaasBaseResponse<DocInfoResDTO> fileUpload(@RequestParam("file") MultipartFile file, HttpServletRequest request) throws IOException {
		 if (file.isEmpty())
	        {
			 LOGGER.info("未发现上传的文件!!!!");
			 throw new PaasBaseException("000001", "未发现上传文件");
	        }
		    String uid = request.getParameter("uid");
		    String userName = request.getParameter("uname");
//	        String dirPath = "F:/upload" ;
	        String dirPath = config.fileStorePath ;
	        String md5Hashcode = Md5Util.getFileStreamMD5((FileInputStream)file.getInputStream(),file.getSize());
	        //真实的文件名存储到数据库中
	        String originalfileName = file.getOriginalFilename();
	        int index = originalfileName.lastIndexOf(".");
	        String fileName = originalfileName.substring(0, index);
	        //文件后缀名
	        String suffixName = originalfileName.substring(index);
	        //生成新的文件名，存储时使用，避免重复上传相同名称的文件，相互覆盖
	        String uuid = UUID.randomUUID().toString().trim().replaceAll("-", "");
	        String storeId = "";
	        Integer size = Long.valueOf(file.getSize()).intValue();
	        String dataPath = this.datePath();//日期路径
	        String relativePath = dataPath + uuid + suffixName;//相对路径
	        String filePath = dirPath + relativePath;//绝对路径
	        //根据hashcode判断文件是否已经上传过，如果已经上传过，就只记录文件信息，不再记录上传文件。
//	        DocInfoBean  docInfo = docInfoService.getDocInfoByHashCode(md5Hashcode);
	        DocInfoVo docInfoVo = new DocInfoVo();
            docInfoVo.setFileName(fileName);
            docInfoVo.setHashCode(md5Hashcode);
            docInfoVo.setRelativePath(relativePath);
            docInfoVo.setSize(size);
            docInfoVo.setSuffixName(suffixName);
            docInfoVo.setUuid(uuid);
	        docInfoVo.setStoreId(uuid);
	        docInfoVo.setUid(uid);
	        docInfoVo.setUserName(userName);
	        File destFile = new File(filePath);
	        // 检测是否存在目录
	        if (!destFile.getParentFile().exists()) {
	        	destFile.getParentFile().mkdirs();// 新建文件夹
	        }
	        try
	        {
	            // 保存文件
	            file.transferTo(destFile);
	            String flag = this.saveFileInfo(docInfoVo);//保存文件信息
	            if("false".equals(flag)){
	            	throw new PaasBaseException("000001", "上传文件失败");
	            }
	            //返回前端数据
	            DocInfoResDTO docInfoResDTO = new DocInfoResDTO();
	            docInfoResDTO.setId(uuid);
	            return new PaasBaseResponse<>(docInfoResDTO);
	        }
	        catch (Exception e)
	        {
	        	e.printStackTrace();
	        	throw new PaasBaseException("000001", "上传文件失败");
	        }
	}
	
	private String saveFileInfo(DocInfoVo docInfoVo){
		/**
		 * 如果用户id为null，就不在处理网盘信息
		 * 根据用户ID获取网盘信息，如果查询不到网盘就新建一个网盘和默认文件夹,
		 * 如果查询到网盘信息，就查询网盘下的文件夹，如果没有就新增一个文件夹，如果查询到多个文件夹，就返回其中一个文件夹的id
		 * */
		String folderId = this.getFolderIdByUserid(docInfoVo);
		docInfoVo.setFolderId(folderId);
		String flag = "";
		flag = this.saveDocinfo(docInfoVo);
        flag = this.saveFilestore(docInfoVo);
		return flag;
	}
	/**
	 * 保存文件信息
	 * */
	private String saveDocinfo(DocInfoVo docInfoVo){
		DocInfoBean  docInfoBean = new DocInfoBean();
        docInfoBean.setId(docInfoVo.getUuid());
        docInfoBean.setIsDeleted(0);
        docInfoBean.setName(docInfoVo.getFileName());
        docInfoBean.setExtType(docInfoVo.getSuffixName());
        docInfoBean.setSize(docInfoVo.getSize());
        docInfoBean.setStoreId(docInfoVo.getStoreId());
        docInfoBean.setHashCode(docInfoVo.getHashCode());
        docInfoBean.setUid(docInfoVo.getUid());
        docInfoBean.setFolderId(docInfoVo.getFolderId());
        boolean flag = docInfoService.saveDocInfo(docInfoBean);
        if(!flag){
        	throw new PaasBaseException("000001","文件信息存储失败！");
        }
        return String.valueOf(flag);
	}
	/**
	 * 保存文件存储信息
	 * */
	private String saveFilestore(DocInfoVo docInfoVo){
		FileStoreBean fileStoreBean = new FileStoreBean();
        fileStoreBean.setDocId(docInfoVo.getUuid());
        fileStoreBean.setDocName(docInfoVo.getFileName());
        fileStoreBean.setMimeType(docInfoVo.getSuffixName());
        fileStoreBean.setId(docInfoVo.getStoreId());
        fileStoreBean.setSize(docInfoVo.getSize());
        fileStoreBean.setFilePath(docInfoVo.getRelativePath());
        Boolean flag = fileStoreService.saveFileStore(fileStoreBean);
        if(!flag){
        	throw new PaasBaseException("000001","文件存储信息保存失败！");
        }
        return String.valueOf(flag);
	}
	
	/**
	 * 根据用户Id获取文件夹ID
	 * */
	private String getFolderIdByUserid(DocInfoVo docInfoVo){
		String userId = docInfoVo.getUid();
		if("".equals(userId)){
			return "";
		}
		DocDiskBean docDiskBean = new DocDiskBean();
		docDiskBean.setUserId(docInfoVo.getUid());
		try{
			List<DocDiskBean> docDiskBeanList =  docDiskService.getList(docDiskBean);
			/**
			 * 如果没有查询到网盘信息，就新增个人网盘和默认文件夹，然后返回默认文件夹ID
			 * */
			String uuid = docInfoVo.getUuid();
			String diskUuid = UUID.randomUUID().toString().trim().replaceAll("-", "");
			String folderUuid = UUID.randomUUID().toString().trim().replaceAll("-", "");
			Boolean flag = true;
			if(docDiskBeanList == null || docDiskBeanList.size() == 0){
				docDiskBean.setDiskName("个人网盘");
				docDiskBean.setId(diskUuid);
				docDiskBean.setIsDeleted(0);
				docDiskBean.setUserId(userId);
				docDiskBean.setUserName(docInfoVo.getUserName());
				docDiskBean.setMaxSpace(1000000);
				flag = docDiskService.saveDocDisk(docDiskBean);
				if(flag){
					DocFolderBean docFolderBean = new DocFolderBean();
					docFolderBean.setId(folderUuid);
					docFolderBean.setName("默认文件夹");
					docFolderBean.setUid(docInfoVo.getUid());
					docFolderBean.setIsDeleted(0);
					docFolderBean.setPid(diskUuid);
					flag = docFolderService.saveDocFolder(docFolderBean);
					if(flag){
						return folderUuid;
					}
				}
				
			}
			/**
			 * 查询到多个网盘的话，取创建时间最早的网盘，理论上，一个用户只能有一个网盘
			 * 如果有网盘却没有文件夹，就创建默认文件夹，返回文件夹ID
			 * 如果有网盘查询到多个文件夹，返回创建时间最早的文件夹ID
			 * */
			if(docDiskBeanList.size() >= 1){
				docDiskBean = docDiskBeanList.get(0);
				DocFolderBean docFolderBean = new DocFolderBean();
				docFolderBean.setPid(docDiskBean.getId());
				List<DocFolderBean> docFolderBeanList = docFolderService.getList(docFolderBean);
				if(docFolderBeanList == null || docFolderBeanList.size() == 0){
					docFolderBean = new DocFolderBean();
					docFolderBean.setId(folderUuid);
					docFolderBean.setName("默认文件夹");
					docFolderBean.setUid(docInfoVo.getUid());
					docFolderBean.setIsDeleted(0);
					docFolderBean.setPid(docDiskBean.getId());
					flag = docFolderService.saveDocFolder(docFolderBean);
					if(flag){
						return folderUuid;
					}
				}else{
					docFolderBean = docFolderBeanList.get(0);
					return docFolderBean.getId();
				}
			}
		}catch(Exception e){
			e.printStackTrace();
			return "";
		}
		
		return "";
	}
	
	@GetMapping(value = "/fileDownload")
    public void fileDownload(HttpServletRequest request, HttpServletResponse res) {
	  String id = request.getParameter("id");
	  String uid = request.getParameter("uid");
	  //根据Id查询文件存储信息
	  FileStoreBean fileStoreBean = fileStoreService.getDocFileStoreInfo(id);
      String fileName = fileStoreBean.getDocName()+fileStoreBean.getMimeType();
      res.setHeader("content-type", "application/octet-stream");
      res.setContentType("application/octet-stream");
      res.setHeader("Content-Disposition", "attachment;filename=\"" + fileName+"\"");
      String dirPath = config.fileStorePath;
      String filePath = dirPath + fileStoreBean.getFilePath();
      byte[] buff = new byte[1024];
      BufferedInputStream bis = null;
      OutputStream os = null;
      try {
        os = res.getOutputStream();
        bis = new BufferedInputStream(new FileInputStream(new File(filePath)));
        int i = bis.read(buff);
        while (i != -1) {
          os.write(buff, 0, i);
          i = bis.read(buff);
        }
        
      } catch (IOException e) {
        e.printStackTrace();
      } finally {
        if (os != null) {
          try {
        	  os.close();
          } catch (IOException e) {
            e.printStackTrace();
          }
        }
        if (bis != null) {
            try {
            	bis.close();
            } catch (IOException e) {
              e.printStackTrace();
            }
          }
      }
      //将下载记录存储到下载记录表中
      DocDownloadRecordBean docDownloadRecordBean = new DocDownloadRecordBean();
      docDownloadRecordBean.setDocId(id);
      docDownloadRecordBean.setUid(uid);
      docDownloadRecordService.saveDocDownloadRecord(docDownloadRecordBean);
	}
	
	private String datePath(){
		Calendar calendar = Calendar.getInstance();
		Integer year = calendar.get(Calendar.YEAR);
		Integer month = calendar.get(Calendar.MONTH)+1;
		Integer day = calendar.get(Calendar.DATE);
		String path = "";
        path =File.separator + year + File.separator +month + File.separator + day + File.separator;
		return path;
	}
}
